package com.dbflow5;

import com.dbflow5.sql.SQLiteType;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;

public class StringUtils{
    /**
     * If the string is not null
     *
     * @param str str
     * @return true if the string is not null, empty string "", or the length is greater than 0
     */
    public static boolean isNullOrEmpty(String str){
        return str == null || str.equals("") || str.isEmpty();
    }

    /**
     * If the string is null
     *
     * @param str str
     * @return true if the string is null, empty string "", or the length is less than equal to 0
     */
    public static boolean isNotNullOrEmpty(String str) {
        return str != null && !str.equals("") && !str.isEmpty();
    }

    public static StringBuilder appendQuotedIfNeeded(StringBuilder src, String string){
        if ("*".equals(string))
            return src.append(string);
        src.append(quoteIfNeeded(string));
        return src;
    }


    private static final char QUOTE = '`';
    private static final Pattern QUOTE_PATTERN = Pattern.compile(QUOTE + ".*" + QUOTE);

    /**
     * Helper method to check if name is quoted.
     *
     * @param string string
     * @return true if the name is quoted. We may not want to quote something if its already so.
     */
    public static boolean isQuoted(String string){
        return QUOTE_PATTERN.matcher(string).find();
    }

    /**
     * The column name to use.
     *
     * @param string The column name to use.
     * @return A name in quotes. E.G. index =&gt; `index` so we can use keywords as column names without fear
     * of clashing.
     */
    public static String quote(String string){
        return QUOTE + string.replace(".", "`.`") + QUOTE;
    }

    public static String quoteIfNeeded(String string){
//        if (string != null && !isQuoted(string)) {
//            return quote(string);
//        } else {
            return string;
//        }
    }

    public static String capitalize(String name) {
        if (name != null && name.length() != 0) {
            char[] chars = name.toCharArray();
            chars[0] = Character.toUpperCase(chars[0]);
            return new String(chars);
        } else {
            return name;
        }
    }

    /**
     * Appends the [SQLiteType] to [StringBuilder]
     *
     * @param stringBuilder src StringBuilder
     * @param sqLiteType    sqLiteType
     * @return result
     */
    public static StringBuilder appendSQLiteType(StringBuilder stringBuilder, SQLiteType sqLiteType){
        return stringBuilder.append(sqLiteType.name());
    }

    /**
     * Strips quotes out of a identifier if need to do so.
     *
     * @param string The name ot strip the quotes from.
     * @return A non-quoted name.
     */
    public static String stripQuotes(String string){
        String ret = string;
//        if (ret != null && isQuoted(ret)) {
//            ret = ret.replace("`", "");
//        }
        return ret;
    }


    /**
     * Appends a value only if it's not empty or null
     *
     * @param stringBuilder src StringBuilder
     * @param name  The name of the qualifier
     * @param value The value to append after the name
     * @return This instance
     */
    public static StringBuilder appendQualifier(StringBuilder stringBuilder, String name, String value){
        if (value != null && !value.isEmpty()) {
            if (name != null) {
                stringBuilder.append(name);
            }
            stringBuilder.append(" "+value+" ");
        }
        return stringBuilder;
    }

    /**
     * Appends the value only if its not null
     *
     * @param stringBuilder src StringBuilder
     * @param value If not null, its string representation.
     * @return This instance
     */
    public static StringBuilder appendOptional(StringBuilder stringBuilder, Object value){
        if (value != null) {
            stringBuilder.append(value);
        }
        return stringBuilder;
    }

    /**
     * Appends an array of these objects by joining them with a comma with
     * [.join]
     *
     * @param stringBuilder src StringBuilder
     * @param objects The array of objects to pass in
     * @return This instance
     */
    public static StringBuilder appendArray(StringBuilder stringBuilder, Object... objects){
        stringBuilder.append(joinToString(Arrays.asList(objects), ", "));
        return stringBuilder;
    }

    /**
     * Appends a list of objects by joining them with a comma with
     * [.join]
     *
     * @param stringBuilder src StringBuilder
     * @param objects The list of objects to pass in
     * @return This instance
     */
    public static StringBuilder appendList(StringBuilder stringBuilder, List<?> objects){
        stringBuilder.append(joinToString(objects, ", "));
        return stringBuilder;
    }

    public static <T> String joinToString(Collection<T> list, String separator){
        StringBuilder builder = new StringBuilder();
        int index = 0;
        for(T t : list){
            builder.append(t.toString());
            if(index != list.size() - 1) {
                builder.append(separator);
            }
            index ++;
        }
        return builder.toString();
    }

    public static <T> String joinToString(Collection<T> list, String separator, Function<T, String> fn){
        StringBuilder builder = new StringBuilder();
        int index = 0;
        for(T t : list){
            builder.append(fn.apply(t));
            if(index != list.size() - 1) {
                builder.append(separator);
            }
            index ++;
        }
        return builder.toString();
    }
}


